#!/usr/bin/env python
# -*- coding:utf-8 -*-

from cmd import Cmd
import os
import sys
try:
    import pefile,capstone,unicorn
except ImportError:
    print("请先安装第三方包:pefile和capstone")
    end = input("回车结束:")
    sys.exit()
import localapi
from lib.utils import printer
import traceback
from settings import reModule

class Cli(Cmd):
    def __init__(self):
        os.system("cls")
        banner = '''
         ____
        |  _ \ _____   _____ _ __ ___  ___ 
        | |_) / _ \ \ / / _ \ '__/ __|/ _ \\
        |  _ <  __/\ V /  __/ |  \__ \  __/
        |_| \_\___| \_/ \___|_|  |___/\___|
        '''
        Cmd.__init__(self)
        self.intro = banner
        self.prompt = 'ReverseConsole>> '
        self.fpath = ""
        self.hmodule = {
                        'bp':"breakpoint.py",
                        'st':'singlestep.py'
                       }
        self.software_bp_addr = None
    def do_menu(self,param):
        for k,v in reModule.items():
            printer.plus(k)
            for m,e in v.items():
                explain = m + " : " + e
                printer.info("   " + explain,flag='')
        
    def do_set(self,param):
        param = param.strip()
        if param == "path":
            fpath = input("请输入文件地址: ")
            isExist = localapi.is_file_exists(fpath.strip())
            if isExist:
                self.fpath = fpath
                printer.info("文件路径设置成功!")
            else:
                printer.warn("文件不存在!")
        elif param == "handle":
            self.sethandle()
        else:
            printer.warn("命令存在!")

    def sethandle(self):
        localapi.api_debug_show_hmodule()
        bhandles = localapi.api_debug_get_bpmoudle()
        shandles = localapi.api_debug_get_ssmoudle()
        inp = input("断点处理模块: ")
        inp = inp.strip()
        if inp not in bhandles:
            printer.warn("模块不存在,使用默认处理模块.")
        else:
            self.hmodule['bp'] = inp
        inp = input("单步调试处理模块: ")
        inp = inp.strip()
        if inp not in shandles:
            printer.warn("模块不存在,使用默认处理模块.")
        else:
            self.hmodule['st'] = inp
    def do_setsbpaddr(self,param):
        param = param.strip()
        self.software_bp_addr = param

    def do_peinfo(self,param):
        param = param.strip()
        if self.fpath:
            if param == "headers":
                localapi.api_pe_headers(self.fpath)
            elif param == "sections":
                localapi.api_pe_sections(self.fpath)
            elif param == "impdll":
                localapi.api_pe_imp_dll_info(self.fpath)
            elif param.find(".dll") > 0:
                localapi.api_pe_dll_info(self.fpath,param)
            elif param == "raw":
                raw = localapi.api_pe_rva_raw(self.fpath)
                printer.test("Raw[文件偏移地址]: " + raw)
            elif param.find("info")>=0:
                order = param.split(".")[1]
                localapi.api_pe_info(self.fpath,order)
        else:
            printer.warn("请先设置文件路径!")
    def do_peanalysis(self,param):
        param = param.strip()
        if self.fpath:
            if param == "strings":
                localapi.api_pe_extract_string(self.fpath)
            elif param.find("str") == 0 and param.find("@") > 0:
                i,s,e = param.split("@")
                localapi.api_pe_extract_string_range(self.fpath,int(s),int(e))
            elif param == "strmal":
                localapi.api_pe_find_str_mal(self.fpath)
            elif param == "funcmal":
                localapi.api_pe_find_func_mal(self.fpath)
        else:
            printer.warn("请先设置文件路径!")
        print("")
    def do_hexedit(self,param):
        try:
            if self.fpath:
                if param == "show":
                    localapi.api_hexedit_show_content(self.fpath)
            else:
                printer.warn("请先设置文件路径!")
            print("")
        except Exception as e:
            traceback.print_exc()
    def do_debugger(self,param):
        param = param.strip()
        if self.fpath:
            if param == "start":
                localapi.api_debug_run(self.fpath,self.hmodule,self.software_bp_addr)
        else:
            printer.warn("请先设置文件路径!")
    def do_calc(self,param):
        param = param.strip()
        result = ""
        if param == "b2d":
            b = input("输入二进制数: ")
            b = b.strip()
            result = localapi.api_calc_b2d(b)
        elif param == "b2o":
            b = input("输入二进制数: ")
            b = b.strip()
            result = localapi.api_calc_b2o(b)
        elif param == "b2h":
            b = input("输入二进制数: ")
            b = b.strip()
            result = localapi.api_calc_b2h(b)
        elif param == "d2b":
            b = input("输入十进制数: ")
            b = b.strip()
            result = localapi.api_calc_d2b(b)
        elif param == "d2o":
            b = input("输入十进制数: ")
            b = b.strip()
            result = localapi.api_calc_d2o(b)
        elif param == "d2h":
            b = input("输入十进制数: ")
            b = b.strip()
            result = localapi.api_calc_d2h(b)
        elif param == "h2b":
            b = input("输入十六进制数[0x开头]: ")
            b = b.strip()
            result = localapi.api_calc_h2b(b)
        elif param == "h2o":
            b = input("输入十六进制数[0x开头]: ")
            b = b.strip()
            result = localapi.api_calc_h2o(b)
        elif param == "h2d":
            b = input("输入十六进制数[0x开头]: ")
            b = b.strip()
            result = localapi.api_calc_h2d(b)
        elif param == "badd":
            a = input("输入二进制数A: ")
            b = input("输入二进制数B: ")
            result = localapi.api_calc_badd(a,b)
        elif param == "bsub":
            a = input("输入二进制数A: ")
            b = input("输入二进制数B: ")
            result = localapi.api_calc_bsub(a,b)
        elif param == "bmul":
            a = input("输入二进制数A: ")
            b = input("输入二进制数B: ")
            result = localapi.api_calc_bmul(a,b)
        elif param == "bdiv":
            a = input("输入二进制数A: ")
            b = input("输入二进制数B: ")
            result = localapi.api_calc_bdiv(a,b)
        elif param == "hadd":
            a = input("输入十六进制数A: ")
            b = input("输入十六进制数B: ")
            result = localapi.api_calc_hadd(a,b)
        elif param == "hsub":
            a = input("输入十六进制数A: ")
            b = input("输入十六进制数B: ")
            result = localapi.api_calc_hsub(a,b)
        elif param == "hmul":
            a = input("输入十六进制数A: ")
            b = input("输入十六进制数B: ")
            result = localapi.api_calc_hmul(a,b)
        elif param == "hdiv":
            a = input("输入十六进制数A: ")
            b = input("输入十六进制数B: ")
            result = localapi.api_calc_hdiv(a,b)
        else:
            printer.warn("参数错误!")
        printer.test("结果: " + str(result))
    
    def do_emulator(self,param):
        param = param.strip()
        ops = param.split('.')
        if ops[0] == 'pe':
            if ops[1] == 'run':
                if ops[2] == 'tech':
                    localapi.api_emu_run_pe_tech()
        elif ops[0] == 'bin':
            if ops[1] == 'run':
                if ops[2] == 'tech':
                    localapi.api_emu_run_shellcode_tech()
                elif ops[2] == "asmcode":
                    asmcode = self.input_asmcode()
                    localapi.api_emu_run_binCode(asmcode)
                elif ops[2] == 'disasm':
                    localapi.api_show_shellcode()
                    binCode = input("请输入二进制代码选项: ")
                    if binCode.strip():
                        archCode = input('请输入CPU架构[I386,AMD64,MIPS,ARM]: ')
                        if archCode:
                            localapi.api_emu_disasm(binCode,archCode)
        elif ops[0] == 'exp':
            if ops[1] == 'query':
                q = input("请输入要查询的汇编指令: ")
                result = ''
                if q:
                    result = localapi.api_get_asm_explain(q)
                if result:
                    printer.info(result)
                else:
                    printer.warn("查询结果为空")
    def input_asmcode(self):
        asmcode = []
        quit = 'q'
        while True:
            code = input("请输入汇编指令[q=退出]: ")
            if code == quit:
                break
            asmcode.append(code)
        return asmcode
    def do_exit(self,param):
        printer.warn("退出!")
        sys.exit()
if __name__ == "__main__":
    try:
        cli = Cli()
        cli.cmdloop()
    except Exception as e:
        traceback.print_exc()
        print("wrong!")